package com.csap.framework.oauth2.server.service.impl;

import com.csap.framework.annotation.apidoc.Description;
import com.csap.framework.oauth2.server.entity.PermissionsEntity;
import com.csap.framework.oauth2.server.entity.RolesPermissionsEntity;
import com.csap.framework.oauth2.server.entity.UserRolesEntity;
import com.csap.framework.oauth2.server.model.UserRolesModel;
import com.csap.framework.oauth2.server.mybatis.UserRolesMapper;
import com.csap.framework.oauth2.server.service.ClientRolesService;
import com.csap.framework.oauth2.server.service.PlatformRolesService;
import com.csap.framework.oauth2.server.service.RolesPermissionsService;
import com.csap.framework.oauth2.server.service.RolesService;
import com.csap.framework.oauth2.server.service.UserPermissionsService;
import com.csap.framework.oauth2.server.service.UserRolesService;
import com.csap.framework.util.CollectionsUtil;
import com.csap.mybatisplus.extension.service.impl.BaseCsapServiceImpl;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户的角色
 * </p>
 *
 * @author yangchengfu
 * @dateTime 2021-07-25 23:51:30
 */
@Service
@Description(value = "用户的角色ServiceImpl")
public class UserRolesServiceImpl extends BaseCsapServiceImpl<UserRolesMapper, UserRolesEntity, UserRolesModel, Long> implements UserRolesService {
    @Resource
    private RolesPermissionsService rolesPermissionsService;
    @Resource
    private PlatformRolesService platformRolesService;
    @Resource
    private ClientRolesService clientRolesService;
    @Resource
    private UserPermissionsService userPermissionsService;
    @Resource
    private RolesService rolesService;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @Override
    public Boolean addUserRoles(String userId, String openId, String platform, String clientId) {
        return clientRolesService.findDefaultRole(platform, clientId)
                .when(i -> i.addAll(platformRolesService.findDefaultRole(platform).get()))
                .value(i -> addUserRoles(i, openId, userId));
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    @Override
    public Boolean addUserRoles(Set<Long> roles, String openId, String userId) {
        if (CollectionsUtil.isEmpty(roles)) {
            return Boolean.FALSE;
        }
        UserRolesModel userRolesModel = new UserRolesModel();
        userRolesModel.setUserId(userId);
        userRolesModel.setOpenId(openId);
        roles.stream().filter(i -> !containsRole(i, userId, openId)).forEach(i -> {
            userRolesModel.setRoleId(i);
            insert(userRolesModel);
        });
        return Boolean.TRUE;
    }

    /**
     * 查找是否 存在该角色
     *
     * @param roleId 角色ID
     * @param openId openId
     * @param userId 用户Id
     * @return 结果
     */
    @Override
    public boolean containsRole(Long roleId, String openId, String userId) {
        return lambdaQuery()
                .select(UserRolesEntity::getId)
                .eq(UserRolesEntity::getUserId, userId)
                .eq(UserRolesEntity::getOpenId, openId)
                .eq(UserRolesEntity::getRoleId, roleId)
                .count() > 0;
    }

    @Override
    public List<Long> roleList(String userId) {
        return roleList(userId, null);
    }

    @Override
    public String roleNameList(String userId, String openId) {
        return String.join(",", rolesService.findDescrByIds(roleList(userId, openId)));
    }

    @Override
    public List<Long> roleList(String userId, String openId) {
        return lambdaQuery()
                .select(UserRolesEntity::getRoleId)
                .eq(UserRolesEntity::getUserId, userId)
                .eq(UserRolesEntity::getOpenId, openId)
                .listField(Long.class)
                .orElse(Collections.emptyList());
    }

    @Override
    public List<String> permissionsList(String userId) {
        return permissions(lambdaQuery()
                .select(UserRolesEntity::getRoleId)
                .eq(UserRolesEntity::getUserId, userId)
                .listMany(rolesPermissionsService)
                .eq(RolesPermissionsEntity::getRoleId, UserRolesEntity::getRoleId)
                .inner(RolesPermissionsEntity::getPermissionsId, PermissionsEntity::getPermissionsId)
                .targetCompare()
                .select(PermissionsEntity::getValue, RolesPermissionsEntity::getPermissions, PermissionsEntity::getValue)
                .end()
                .targetWhere()
                .eq(PermissionsEntity::getEnabled, Boolean.TRUE)
                .end()
                .end()
                .list()
                .end(UserRolesEntity::getRolesPermissions)
                .list()
                .stream()
                .map(UserRolesEntity::getRolesPermissions)
                .flatMap(Collection::stream)
                .map(RolesPermissionsEntity::getPermissions)
                .map(PermissionsEntity::getValue)
                .collect(Collectors.toList()), userPermissionsService.permissions(userId));
    }

    private List<String> permissions(List<String> p1, Set<String> p2) {
        List<String> strings = Lists.newArrayList(p1);
        strings.addAll(p2);
        return strings;
    }

    @Override
    public boolean removeByUserId(String openId, String userId) {
        return UserRolesService.super.removeByUserId(openId, userId);
    }

    @Override
    public boolean removeByUserId(UserRolesModel rolesModel) {
        return UserRolesService.super.removeByUserId(rolesModel);
    }
}
